﻿using System;

namespace Kyoh.Lib.Excel
{
    /// <summary>セル、行、列、1 つ以上のセル範囲を含む選択範囲、または 3-D 範囲を表します</summary>
	public class Range : Component
	{
		private Range(object exRange, Component parent)
			: base(exRange, parent)
		{
		}

        /// <summary>Excel COM オブジェクトで、新しいインスタンスを初期化します。</summary>
        /// <param name="obj">Excel COM オブジェクト</param>
        /// <param name="parent">親となる <see cref="Component"/> オブジェクト。</param>
		internal static Range Create(object obj, Component parent)
		{
			return obj == null ? null : new Range(obj, parent);
		}

		#region A-C

        /// <summary>セルをアクティブにします。</summary>
		public void Activate()
		{
			base.InvokeMethod("Activate");
		}

        /// <summary>セルにコメントを追加します。</summary>
        /// <param name="text">追加するコメント文字列。</param>
		public void AddComment(string text)
		{
			base.InvokeMethod("AddComment", text);
		}

        /// <summary>セルの大きさを内容に合わせて変更します。</summary>
		public void AutoFit()
		{
			base.InvokeMethod("AutoFit");
		}

        /// <summary>セルの周囲に罫線を追加します。</summary>
		public void BorderAround()
		{
            //UNDONE: 引数の追加。
			base.InvokeMethod("BorderAround");
		}

        /// <summary>セルの罫線を設定します。</summary>
		public Borders Borders
		{
			get { return Borders.Create(base.GetProperty("Borders"), this); }
		}

        /// <summary>セルの数式を計算します。</summary>
		public void Calculate()
		{
			base.InvokeMethod("Calculate");
		}

        /// <summary>セルの列位置を取得します。</summary>
		public int Column
		{
			get { return (int)base.GetProperty("Column"); }
		}

        /// <summary>セルの列を取得します。</summary>
		public Range Columns
		{
			get { return new Range(base.GetProperty("Columns"), this); }
		}
        
        /// <summary>セルの列幅を取得・設定します。</summary>
		public int? ColumnWidth
		{
			get { return base.GetProperty("ColumnWidth") as int?; }
			set { base.SetProperty("ColumnWidth", value); }
		}

        /// <summary>セルの数を取得します。</summary>
		public int Count
		{
			get { return (int)base.GetProperty("Count"); }
		}

        /// <summary>セルの値・書式を消去します。</summary>
		public void Clear()
		{
			base.InvokeMethod("Clear");
		}

        /// <summary>セルのコメントを削除します。</summary>
		public void ClearComments()
		{
			base.InvokeMethod("ClearComments");
		}

        /// <summary>セルの値を消去します。</summary>
		public void ClearContents()
		{
			base.InvokeMethod("ClearContents");
		}

        /// <summary>セルの書式を消去します。</summary>
		public void ClearFormats()
		{
			base.InvokeMethod("ClearFormats");
		}

        /// <summary>セルからメモを消去します。</summary>
		public void ClearNotes()
		{
			base.InvokeMethod("ClearNotes");
		}

        /// <summary>セルのアウトラインを消去します。</summary>
		public void ClearOutline()
		{
			base.InvokeMethod("ClearOutline");
		}

        /// <summary>セルをコピーします。</summary>
        /// <param name="destination">コピー先のセルを指定します。指定しないか、nullを指定した場合、セルをクリップボードにコピーします。</param>
		public void Copy(Range destination = null)
		{
			base.InvokeMethod("Copy", destination == null ? Type.Missing : destination.ExcelComObject);
		}

        /// <summary>セルを切取ります。</summary>
        /// <param name="destination">移動先のセルを指定します。指定しないか、nullを指定した場合、セルをクリップボードに切取ります。</param>
		public void Cut(Range destination = null)
		{
			base.InvokeMethod("Cut", destination == null ? Type.Missing : destination.ExcelComObject);
		}

		#endregion

		#region D-F

        /// <summary>セルを削除します。</summary>
        /// <param name="shift">削除後のセルの移動方法。</param>
		public void Delete(DeleteShiftDirection? shift = null)
		{
			base.InvokeMethod("Delete", (shift != null && shift.HasValue) ? shift.Value : Type.Missing);
		}

        /// <summary>セルの列全体を取得します。</summary>
		public Range EntireColumn
		{
			get { return new Range(base.GetProperty("EntireColumn"), this); }
		}

        /// <summary>セルの行全体を取得します。</summary>
		public Range EntireRow
		{
			get { return new Range(base.GetProperty("EntireRow"), this); }
		}

        /// <summary>範囲内の下方向のセルに値をコピーします。</summary>
		public void FillDown()
		{
			base.InvokeMethod("FillDown");
		}

        /// <summary>範囲内の左方向のセルに値をコピーします。</summary>
		public void FillLeft()
		{
			base.InvokeMethod("FillLeft");
		}

        /// <summary>範囲内の右方向のセルに値をコピーします。</summary>
        public void FillRight()
		{
			base.InvokeMethod("FillRight");
		}

        /// <summary>範囲内の上方向のセルに値をコピーします。</summary>
        public void FillUp()
		{
			base.InvokeMethod("FillUp");
		}

        /// <summary>セルのフォントを取得します。</summary>
		public Font Font { get { return Font.Create(base.GetProperty("Font"), this); } }

        /// <summary>セルの数式を取得・設定します。</summary>
		public string Formula
		{
			get { return (string)base.GetProperty("Formula"); }
			set { base.SetProperty("Formula", value); }
		}

        /// <summary>セルの数式をR1C1形式で取得・設定します。</summary>
		public string FormulaR1C1
		{
			get { return (string)base.GetProperty("FormulaR1C1"); }
			set { base.SetProperty("FormulaR1C1", value); }
		}

		#endregion
	
		#region H-J

		/// <summary>セルに数式が設定されているかどうかを取得・設定します。</summary>
        public bool? HasFormula
		{
			get { return base.GetProperty("HasFormula") as bool?; }
			set
			{
				if (value != null && value.HasValue)
					base.SetProperty("HasFormula", value.Value);
			}
		}

        /// <summary>セルの水平位置を取得・設定します。</summary>
		public HorizontalAlignment? HorizontalAlignment
		{
			get { return base.GetProperty("HorizontalAlignment") as HorizontalAlignment?; }
			set
			{
				if (value != null && value.HasValue)
					base.SetProperty("HorizontalAlignment", value.Value);
			}
		}

        /// <summary>セルの垂直位置を取得・設定します。</summary>
        public int? IndentLevel
		{
			get { return base.GetProperty("IndentLevel") as int?; }
			set
			{
				if (value != null && value.HasValue)
					base.SetProperty("IndentLevel", value.Value);
			}
		}

		/*
		public Interior Interior
		{
			get { return new Interior(base.GetProperty("Interior"), this); }
		}
		//*/

        #endregion

		#region M-O

        /// <summary>セルを結合します。</summary>
        /// <param name="accross">水平方向にのみ結合する場合は <c>true</c> 、規定値は <c>false</c> 。</param>
		public void Merge(bool accross = false)
		{
			base.InvokeMethod("Merge", accross);
		}

        /// <summary>結合済みのセル範囲を取得します。</summary>
		public Range MergeArea
		{
			get { return new Range(base.GetProperty("MergeArea"), this); }
		}

        /// <summary>セルが結合されているかどうかを取得します。</summary>
		public bool? MergeCells
		{
			get { return base.GetProperty("MergeCells") as bool?; }
		}

        /// <summary>セルの名前を取得・設定します。</summary>
		public string Name
		{
			get { return (string)base.GetProperty("Name"); }
			set { base.SetProperty("Name", value); }
		}

        /// <summary>次のセルを取得します。</summary>
		public Range Next
		{
			get { return new Range(base.GetProperty("Next"), this); }
		}

        /// <summary>セルの数値書式を取得・設定します。</summary>
		public string NumberFormat
		{
			get { return (string)base.GetProperty("NumberFormat"); }
			set { base.SetProperty("NumberFormat", value); }
		}

        /// <summary>現在のセルから、指定の行数・列数分移動したセルを取得します。</summary>
        /// <param name="rowOffset">移動する行数。</param>
        /// <param name="columnOffset">移動する列数。</param>
        /// <returns>現在のセルから、指定の行数・列数分移動したセル。</returns>
		public Range Offset(long rowOffset = 0, int columnOffset = 0)
		{
			return new Range(base.GetProperty("Offset", rowOffset, columnOffset), this);
		}

		#endregion

		#region P-R

        /// <summary>形式を指定してクリップボードを貼り付けます。</summary>
        /// <param name="Paste">貼り付ける値の種類。</param>
        /// <param name="Operation">貼り付け先に対する計算方法。</param>
        /// <param name="SkipBlanks">空のセルをスキップするかどうか。</param>
        /// <param name="Transpose">行と列を入れ替えるかどうか。</param>
        /// <returns>貼り付けが正常に行われた場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
        public bool PasteSpecial(PasteType Paste = PasteType.All, PasteSpecialOperation Operation = PasteSpecialOperation.None, bool? SkipBlanks = null, bool? Transpose = null)
        {
            return (bool)base.InvokeMethod("PasteSpecial",
                (int)Paste,
                (int)Operation,
                SkipBlanks ?? Type.Missing,
                Transpose ?? Type.Missing);
        }

        /// <summary>前のセルを取得します。</summary>
		public Range Previous
		{
			get { return new Range(base.GetProperty("Previous"), this); }
		}

        /// <summary>重複した値を削除します。</summary>
        /// <param name="Columns">重複判定を行う列位置の配列。</param>
        /// <param name="Header">1行目をヘッダとして扱うかどうか。</param>
        public void RemoveDuplicates(int[] Columns = null, YesNoGuess Header = YesNoGuess.No)
        {
            base.InvokeMethod("RemoveDuplicates",
                Columns ?? Type.Missing,
                Header);
        }

        /// <summary>現在のセルから指定の行数・列数だけ範囲を拡大したセルを取得します。</summary>
        /// <param name="rowSize">拡大する行数。</param>
        /// <param name="columnSize">拡大する列数。</param>
        /// <returns>現在のセルから指定の行数・列数だけ範囲を拡大したセル。</returns>
        public Range Resize(long rowSize = 0, int columnSize = 0)
		{
			return new Range(base.GetProperty("Resize", rowSize, columnSize), this);
		}

        /// <summary>セルの行位置を取得します。</summary>
		public int Row
		{
			get { return (int)base.GetProperty("Row"); }
		}

        /// <summary>セルの列高さを取得・設定します。</summary>
		public int? RowHeight
		{
			get { return base.GetProperty("RowHeight") as int?; }
			set { base.SetProperty("RowHeight", value); }
		}

        /// <summary>セルの行を取得します。</summary>
		public Range Rows
		{
			get { return new Range(base.GetProperty("Rows"), this); }
		}

		#endregion

		#region S-U

        /// <summary>セルを選択します。</summary>
		public void Select()
		{
			base.InvokeMethod("Select");
		}

        /// <summary>セルを表示します。</summary>
		public void Show()
		{
			base.InvokeMethod("Show");
		}

        /// <summary>セルの値を文字列として取得します。</summary>
		public string Text
		{
			get { return (string)base.GetProperty("Text"); }
		}

        /// <summary>セルの結合を解除します。</summary>
		public void UnMerge()
		{
			base.InvokeMethod("UnMerge");
		}

		#endregion

        /// <summary>セルの値を取得・設定します。</summary>
		public object Value
		{
			get { return base.GetProperty("Value"); }
			set { base.SetProperty("Value", value); }
		}

        /// <summary>セルの垂直位置を取得・設定します。</summary>
		public VerticalAlignment? VerticalAlignment
		{
			get { return base.GetProperty("VerticalAlignment") as VerticalAlignment?; }
			set
			{
				if (value != null && value.HasValue)
					base.SetProperty("VerticalAlignment", value.Value);
			}
		}

        /// <summary>セルの含まれるワークシートを取得します。</summary>
		public Worksheet Worksheet
		{
			get { return Worksheet.Create(base.GetProperty("Worksheet"), this); }
		}

        /// <summary>セル内の行位置・列位置を指定して、単一セルを取得します。</summary>
        /// <param name="row">行位置。</param>
        /// <param name="column">列位置。</param>
		public Range this[int row, int column]
		{
			get
			{
				if (row < 1 || 1048576 < row)
					throw new ArgumentOutOfRangeException("row", row, "Excelの行は1～65,536(または1,048,576)です");
				if (column < 1 || 16384 < column)
					throw new ArgumentOutOfRangeException("column", column, "Excelの列は1～256(または16,384)です");

				return new Range(base.GetProperty("Item", row, column), this);
			}
		}

        /// <summary>セル内の行位置・列位置を指定して、単一セルを取得します。</summary>
        /// <param name="row">行位置。</param>
        /// <param name="column">列位置。</param>
		public Range this[int row, string column]
		{
			get
			{
				if (row < 1 || 1048576 < row)
					throw new ArgumentOutOfRangeException("row", row, "Excelの行は1～65,536(または1,048,576)です");
				return new Range(base.GetProperty("Item", row, column), this);
			}
		}

        /// <summary>セル内のインデックスを指定して、単一セルを取得します。</summary>
        /// <param name="index">インデックス。</param>
		public Range this[int index]
		{
			get { return new Range(base.GetProperty("Item", index), this); }
		}

        /// <summary>セル内のインデックスを指定して、単一セルを取得します。</summary>
        /// <param name="index">インデックス。</param>
		public Range this[string index]
		{
            get { return new Range(base.GetProperty("Range", index), this); }
		}

        /// <summary>セル内のインデックスを指定して、単一セルを取得できるかどうかを試験します。</summary>
        /// <param name="index">インデックス。</param>
        /// <param name="range">取得できた場合に対象のセルを格納する出力パラメータ。</param>
        /// <returns>取得できた場合は <c>true</c> 、それ以外の場合値は <c>false</c> 。</returns>
        public bool TryGetRange(string index, out Range range)
        {
            range = null;
            try
            {
                range = new Range(base.GetProperty("Range", index, Type.Missing), this);
                return true;
            }
            catch { return false; }
        }

        /// <summary>セル範囲を指定して、セルを取得します。</summary>
        /// <param name="cell1">開始位置のセル。</param>
        /// <param name="cell2">終了位置のセル。</param>
		public Range this[Range cell1, Range cell2]
		{
            get { return new Range(base.GetProperty("Item", cell1.ExcelComObject, cell2.ExcelComObject), this); }
		}

	}
}